package com.test.loading;

import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;

import com.test.drawing.Animation;
import com.test.drawing.AnimationBuffer;
import com.test.drawing.BoardMesh;
import com.test.drawing.MeshBuffer;
import com.test.drawing.Player.Team;
import com.test.field.R;

/**
 * ModelLoadManager<br>
 * Controls the Loading and Creation of Animations
 */
public class ModelLoadManager {

	// Data Information
	private final static String MODEL_PATH = "lowerBall.vfm";
	private final static String SIGN_PATH = "placa.vfm";

	// Bitmaps
	private static Bitmap team1_texture = null;
	private static Bitmap team2_texture = null;

	// Context

	private static Context appContext;

	// Data
	private static AnimationBuffer scene;
	private static MeshBuffer signScene;

	/**
	 * Verify if the Scenes are already Loaded
	 * 
	 * @return True - Scenes has already been loaded<br>
	 *         False - Scenes not loaded yet
	 */
	public static boolean isSceneLoaded() {
		return scene != null && signScene != null;
	}

	/**
	 * Creates an Animation from the Loaded Scene
	 * 
	 * @param team
	 *            Texture's Team to be Setted
	 * @return Texturized Animation
	 */
	/**
	 * @param team
	 * @return
	 */
	public static Animation createAnimation(Team team) {

		if (scene == null)
			return null;

		Animation a = new Animation(scene);

		if (team == Team.First_Team)
			a.loadBitmap(team1_texture);
		else if (team == Team.Second_Team)
			a.loadBitmap(team2_texture);

		return a;
	}

	/**
	 * Sets the Current Texture of Models
	 * 
	 * @param texture1
	 *            Texture to be used in Team 1
	 * @param texture2
	 *            Texture to be used in Team 2
	 */
	public static void setTextures(Bitmap texture1, Bitmap texture2) {
		team1_texture = texture1 != null ? texture1 : team1_texture;
		team2_texture = texture2 != null ? texture2 : team2_texture;
	}

	/**
	 * Creates a new BoardMesh using the Loaded Sign Scene
	 * 
	 * @return BoardMesh
	 */
	public static BoardMesh createBoard() {
		return new BoardMesh(signScene, appContext.getResources().getDrawable(
				R.drawable.sign_background));
	}

	/**
	 * Starts loading the Model (in another thread) from the context's assets
	 * 
	 * @param context
	 *            Context to be used
	 */
	public static void startModelLoading(Context context) {

		appContext = context;

		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				loadModel(); // Loads Model
			}
		});

		t.start();
	}

	/*
	 * Loads the Models
	 */
	private static void loadModel() {

		Log.i("Loading", "Starting Model Loading");

		try {
			
			// Loads the Model
			scene = new AnimationBuffer(loadScene(appContext, MODEL_PATH));
			signScene = new MeshBuffer(loadScene(appContext, SIGN_PATH));

		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		Log.i("Loading", "Finished Model Loading");
	}

	/*
	 * Loads a Scene based in the .vfm format
	 */
	private static Scene loadScene(Context c, String filename)
			throws IOException, ClassNotFoundException {

		Scene s = new Scene();

		DataInputStream dis = new DataInputStream(c.getAssets().open(filename));

		// Read the Indice Size Buffer
		int bufferSize = dis.readInt();

		// Creates the Buffer
		byte[] buffer = new byte[bufferSize];
		dis.read(buffer);

		// Created the ShortBuffer based in the bytes read
		ShortBuffer sb = ByteBuffer.wrap(buffer).asShortBuffer();
		s.setIndices(new short[sb.capacity()]);
		sb.get(s.getIndices());

		// Read the Texture Size Buffer
		bufferSize = dis.readInt();
		buffer = new byte[bufferSize];
		dis.read(buffer);

		// Created the FloatBuffer based in the bytes read
		FloatBuffer fb = ByteBuffer.wrap(buffer).asFloatBuffer();
		s.setTexCoordinates(new float[fb.capacity()]);
		fb.get(s.getTextureCoordinates());

		// Read the Normals Size Buffer
		bufferSize = dis.readInt();
		buffer = new byte[bufferSize];
		dis.read(buffer);

		// Created the FloatBuffer based in the bytes read
		fb = ByteBuffer.wrap(buffer).asFloatBuffer();
		s.setNormalsCoordinates(new float[fb.capacity()]);
		fb.get(s.getNormalsCoordinates());

		// Read the Frames Size
		int framesSize = dis.readInt();

		Frame f = null;

		for (int i = 0; i < framesSize; i++) {

			// Read the Frame Vertices' Size Buffer
			bufferSize = dis.readInt();
			buffer = new byte[bufferSize];
			int ret = dis.read(buffer);

			if (ret > -1) {
				// Created the FloatBuffer based in the bytes read
				fb = ByteBuffer.wrap(buffer).asFloatBuffer();
				f = new Frame(new float[fb.capacity()]);
				fb.get(f.getVertices());

				s.getFramesList().add(f);
			}
		}

		dis.close();
		return s;
	}
}
